package top.ajunnihao.core.web.controller;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.multipart.MultipartFile;
import top.ajunnihao.core.entity.Message;
import top.ajunnihao.core.entity.User;
import top.ajunnihao.core.entity.UserAbility;
import top.ajunnihao.core.service.MessageService;
import top.ajunnihao.core.service.UserAbilityService;
import top.ajunnihao.core.spring.exception.NotFoundException;
import top.ajunnihao.core.util.AJunUtils;
import top.ajunnihao.core.util.FileStore;
import top.ajunnihao.core.util.TmpFile;
import top.ajunnihao.core.util.page.PageInfo;
import top.ajunnihao.core.util.resp.JResp;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * TODO 帖子控制器
 *
 * @author AJun
 * @version 1.0.0
 * @date 2020/5/24
 */
@Controller
public class MessageController {

    private static final String USER = "USER"; // Session 的名称
    private static final String USER_ABILITY = "USER_ABILITY";
    private static final int MESSAGE_PAGE_SIZE = 7; // 每页显示主贴数量
    private static final int MESSAGE_REPLY_PAGE_SIZE = 3; // 每页显示回复数量
    public static FileStore store = new FileStore("/usr/local/ajun/bbsfile/message/", "/bbsfile/message/");
//    public static FileStore store = new FileStore("C:/bbsfile/message/", "/bbsfile/message/");

    @Autowired
    private MessageService messageService;
    @Autowired
    private UserAbilityService userAbilityService;

    /**
     * 列表帖子页，不需要登录即可查看
     */
    @GetMapping(value = {"/messages", "/", ""})
    public String list(@RequestParam(value = "pageNum", defaultValue = "1", required = false) int pageNum,
                       Model model) {
        // 分页查询全部帖子
        PageInfo<Message> pageInfo = messageService.findMessageByPage(pageNum, MESSAGE_PAGE_SIZE);
        model.addAttribute("pageInfo", pageInfo);

        // 查询精华帖子
        List<Message> niceMsgList = messageService.findNiceMsg();
        model.addAttribute("niceMsgList", niceMsgList);

        // 查询最新的四条帖子
        List<Message> newMsgList = messageService.findNewMsg();
        model.addAttribute("newMsgList", newMsgList);
        return "message/list";
    }

    /**
     * 新增帖子页
     */
    @GetMapping("/u/message/add")
    public String add() {
        return "message/add";
    }

    /**
     * 新增帖子
     */
    @PostMapping("/u/message/add.do")
    @ResponseBody
    public Object addMsg(@RequestBody Message message,
                         @SessionAttribute(USER) User user,
                         @SessionAttribute(USER_ABILITY) UserAbility userAbility,
                         HttpServletRequest request) {
        // 保存之前，检查用户的权利
        if (userAbility.getMsgCount() <= 0) {
            return JResp.fail("您今日发帖数量过多，请明天再来! 您每日最多发帖: " + userAbility.getMsgMax() + "条");
        }

        // title 和 content是前端传来的
        message.setCreator(user.getId());
        message.setRef1(0L); // ref1 = 0 表示这一条是主贴
        message.setTimeCreate(new Date()); // 发帖时间
        message.setTimeUpdate(new Date()); // 帖子更新时间
        message.setReplyUser(user.getId());
        message.setReplyName(user.getName());
        message.setReplyText(message.getTitle());
        message.setReplyTime(message.getTimeCreate());
        // 附件图片存储路径 示例 201911/01/15725791906031/
        message.setStorePath(makeStorePath());
        // 图片处理
        message.setImg1(moveTmpToStore(request, message.getStorePath(), message.getImg1()));
        message.setImg2(moveTmpToStore(request, message.getStorePath(), message.getImg2()));
        message.setImg3(moveTmpToStore(request, message.getStorePath(), message.getImg3()));

        // 调用 service 保存
        boolean okFlag = messageService.saveMessage(message);
        if (!okFlag) {
            // 保存失败
            return JResp.fail("保存失败");
        }

        // 保存之后，扣除用户权利(发帖数 -1)
        userAbility.setMsgCount(userAbility.getMsgCount() - 1);
        userAbilityService.updateUserAbility(userAbility);
        return JResp.success("保存成功");
    }

    /**
     * 帖子详情页，不需要登录即可查看
     */
    @GetMapping("/message/detail")
    public String msgDetail(@RequestParam(value = "pageNum", defaultValue = "1", required = false) int pageNum,
                            @RequestParam Long msgId,
                            Model model) {
        // 查询主贴
        Message message = messageService.findMessageById(msgId);
        if (message == null) {
            throw new NotFoundException("无次记录，messageId = " + msgId);
        } else {
            // 处理 'img1', 'img2', 'img3'字段，转成显示用的URL
            String prefix = store.getUrl(message.getStorePath());
            if (!StringUtils.isEmpty(message.getImg1())) {
                message.setImg1(prefix + message.getImg1());
            }
            if (!StringUtils.isEmpty(message.getImg2())) {
                message.setImg2(prefix + message.getImg2());
            }
            if (!StringUtils.isEmpty(message.getImg3())) {
                message.setImg3(prefix + message.getImg3());
            }
            model.addAttribute("message", message);
        }

        // 查询回复
        PageInfo<Message> pageInfo = messageService.findMessageReplyByPage(msgId, pageNum, MESSAGE_REPLY_PAGE_SIZE);
        model.addAttribute("pageInfo", pageInfo);
        // 回复楼层基数，0,3,6...
        model.addAttribute("baseIndex", MESSAGE_REPLY_PAGE_SIZE * (pageNum - 1));
        return "message/detail";
    }

    /**
     * 新增回复
     */
    @PostMapping("/u/message/reply/add.do")
    @ResponseBody
    public Object addReply(@RequestBody JSONObject jReq,
                           @SessionAttribute(USER) User user,
                           @SessionAttribute(USER_ABILITY) UserAbility userAbility) {
        // 保存之前，检查用户的权利
        if (userAbility.getReplyCount() <= 0) {
            return JResp.fail("您今日回复数量过多，请明天再来! 您每日最多回复: " + userAbility.getReplyMax() + "条");
        }

        // 查询主贴
        Long msgId = jReq.getLongValue("msgId");
        Message message = messageService.findMessageById(msgId);
        if (message == null) {
            throw new NotFoundException("无次记录，messageId = " + msgId);
        }

        // 创建一条回复记录
        Message reply = new Message();
        reply.setCreator(user.getId());
        reply.setTitle(jReq.getString("title"));
        reply.setContent(jReq.getString("content"));
        reply.setRef1(message.getId()); // 原文 id，即主贴 id
        reply.setTimeCreate(new Date());
        reply.setTimeUpdate(new Date());
        reply.setCat1(message.getCat1());
        reply.setCat2(message.getCat2());
        reply.setCat3(message.getCat3());
        reply.setStorePath(makeStorePath());

        // 调用 service 保存
        messageService.saveMessage(reply);

        // 更新主贴数据
        message.setTimeUpdate(new Date());
        message.setNumReply(message.getNumReply() + 1); // 回复数 +1
        message.setReplyUser(reply.getCreator());
        message.setReplyName(user.getName());
        message.setReplyTime(new Date());
        message.setReplyText(reply.getTitle());
        boolean okFlag = messageService.updateMessage(message);
        if (!okFlag) {
            // 保存失败
            return JResp.fail("保存失败");
        }

        // 保存之后，扣除用户权利(回复数 -1)
        userAbility.setReplyCount(userAbility.getReplyCount() - 1);
        userAbilityService.updateUserAbility(userAbility);
        return JResp.success("保存成功");
    }

    /**
     * 用户对帖子的操作: 删除自己的帖子
     */
    @PostMapping("/u/message/setUserFlag.do")
    @ResponseBody
    public Object setUserFlag(@RequestBody JSONObject jReq, @SessionAttribute("USER") User user) {
        // 该帖子 id
        long msgId = jReq.getLongValue("msgId");
        // 操作命令
        String cmd = jReq.getString("cmd");

        // 确定是否是用户自己删自己的帖子(查询该帖子的用户id，与 session 中的用户 id 进行比对)
        Message message = messageService.findMessageById(msgId);
        if (message.getCreator().intValue() != user.getId()) {
            // 不能删除别人的帖子
            return JResp.fail("您无权删除别人的帖子");
        }

        // 删除此帖子以及其回复(假删除，设置其 delFlag 为 1)
        return messageService.setMsgFlags(cmd, msgId);
    }

    /**
     * 管理员对帖子的操作: 置顶、加精、删除
     */
    @PostMapping("/u/message/adminSetUserFlag.do")
    @ResponseBody
    public Object adminSetFlags(@RequestBody JSONObject jReq, @SessionAttribute("USER") User user) {
        // 判断是否为管理员操作
        if (user.getIsAdmin() == null || !user.getIsAdmin()) {
            return JResp.fail("仅管理员可操作");
        }

        // 该帖子 id
        long msgId = jReq.getLongValue("msgId");
        // 操作命令
        String cmd = jReq.getString("cmd");

        // 根据 id 查询帖子，判断此贴是否存在
        Message message = messageService.findMessageById(msgId);
        if (message == null) {
            return JResp.fail("此帖不存在，msgId=" + msgId);
        }

        // 操作
        return messageService.setMsgFlags(cmd, msgId);
    }

    /**
     * 附件图片上传
     */
    @PostMapping("/u/message/imgUpload.do")
    @ResponseBody
    public Object attachmentUpload(@RequestParam("file") MultipartFile file,
                                   HttpServletRequest request,
                                   @SessionAttribute(USER_ABILITY) UserAbility userAbility) {
        // 保存之前，检查用户的权利
        if (userAbility.getImageCount() <= 0) {
            return JResp.fail("您今日上传图片数量过多，请明天再来! 您每日最多上传: " + userAbility.getImageMax() + "张图片");
        }

        Map<String, Object> result = new HashMap<String, Object>();
        if (file != null && !file.isEmpty()) {
            String realName = file.getOriginalFilename(); // 文件原始名称
            if (StringUtils.isEmpty(realName)) {
                return JResp.fail(result, "请上传文件");
            }
            String suffix = AJunUtils.getSuffix(realName); // 文件后缀
            String tmpName = AJunUtils.guid2() + suffix; // 临时文件名称

            // 项目真实路径
            File realDir = new File(request.getServletContext().getRealPath("/tmp"));
            realDir.mkdirs();
            // 临时文件目录
            File tmpFile = new File(realDir, tmpName);
            try {
                // 上传文件
                file.transferTo(tmpFile);
                if (tmpFile.length() > 3000000) {
                    return JResp.fail(result, "图片太大!需小于3M!");
                }

                // 上传图片之后，扣除用户权利(上传图片数 -1)
                userAbility.setImageCount(userAbility.getImageCount() - 1);
                userAbilityService.updateUserAbility(userAbility);

                // 回应给客户端的信息
                String tmpUrl = request.getContextPath() + "/tmp/" + tmpName; // 临时文件访问 url
                result.put("realName", realName); // 文件原始名称
                result.put("tmpName", tmpName); // 临时文件名称
                result.put("tmpUrl", tmpUrl); // 临时文件访问 url
                return JResp.success(result, "上传成功");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return JResp.fail(result, "上传失败");
        }
        return JResp.fail(result, "请上传文件");
    }

    /**
     * 将临时文件存储到实际路径Store，并返回存储路径 (此处只存储文件名)
     */
    private String moveTmpToStore(HttpServletRequest request, String storePath, String tmpName) {
        if (StringUtils.isEmpty(tmpName))
            return "";
        // 临时文件
        File tmpFile = TmpFile.getFile(request, tmpName);
        // 实际存储路径
        File storeDir = store.getFile(storePath);
        try {
            // 临时文件移动到实际存储路径
            FileUtils.moveFileToDirectory(tmpFile, storeDir, true);
            return tmpName;
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 图片存储路径
     */
    public String makeStorePath() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM/dd/");
        return sdf.format(new Date()) + AJunUtils.guid2() + "/";
    }

    public void test() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
